package whf.framework.ext;

import java.util.Iterator;
import java.util.List;

import org.springframework.orm.hibernate3.HibernateTemplate;

import whf.framework.cache.Cache;
import whf.framework.cache.CacheManager;
import whf.framework.dao.hibernate.HibernateHelper;
import whf.framework.datasource.DataSource;
import whf.framework.datasource.EmptyDataSource;
import whf.framework.datasource.impl.CollectionDataSource;
import whf.framework.entity.Entity;
import whf.framework.exception.AppException;
import whf.framework.ext.entity.Category;
import whf.framework.ext.entity.DictItem;
import whf.framework.ext.helper.DictHelper;
import whf.framework.ext.helper.DictHelperFactory;
import whf.framework.ext.service.CategoryService;
import whf.framework.ext.service.DictItemService;
import whf.framework.log.Log;
import whf.framework.log.LogFactory;
import whf.framework.service.SpringService;
import whf.framework.util.BeanFactory;
import whf.framework.util.StringUtils;
import whf.framework.util.Utils;

/**
 * 使用一种方便的方法获取字典对象，并且可以缓存
 * @author wanghaifeng
 * @create Dec 22, 2006 9:48:48 AM
 * 
 */
@SuppressWarnings("unchecked")
public class DictManagerImp extends SpringService implements DictManager{
	private static Log log = LogFactory.getLog(DictManagerImp.class);
	private static DictManager dictManager;
	
	private CategoryService categoryService;
	private DictItemService dictItemService;
	private CacheManager cacheManager;
	
	/**
	 * 缓存格式<categoryCode:Map<dictItemCode:dictItem>>
	 * @property Cache:cache
	 */
	private Cache<String, DataSource<DictItem>> cache;
	
	/**
	 * cache是否已经初始化
	 * @property boolean:cacheInitialized
	 */
	private boolean cacheInitialized;
	
	public void setCategoryService(CategoryService service){
		this.categoryService = service;
	}
	
	public void setDictItemService(DictItemService service){
		this.dictItemService = service;
	}
	
	public void setCacheManager(CacheManager cacheManager){
		this.cacheManager = cacheManager;
	}
	
	private Cache<String, DataSource<DictItem>> getCache(){
		//if(!ApplicationConfig.getInstance().isProductMode()) return null;
		if(this.cacheInitialized)
			return this.cache;
		this.cache = this.cacheManager.getCache(DictManagerImp.class.getName());
		this.cacheInitialized = true;
		return this.cache;
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.ext.DictManager#findDictItem(java.lang.String, java.lang.String)
	 */
	public DictItem findDictItem(String categoryCodeOrEnumClassName, String dictItemCode){
		DataSource<DictItem> items = this.findByCategoryCode(categoryCodeOrEnumClassName, null);
		if(items == null) return null;
		for(Iterator<DictItem> it = items.iterator(); it.hasNext(); ){
			DictItem item = it.next();
			if(StringUtils.equalsIgnoreCase(dictItemCode, item.getCode())){
				return item;
			}
		}
		return null;
	}
	
	public static DictManager getDictManager(){
		if(dictManager == null)
			dictManager = (DictManager)BeanFactory.getBean("framework.DictManager");
		return dictManager;
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.ext.DictManager#findByCategory(whf.framework.ext.entity.Category)
	 */
	public DataSource<DictItem> findByCategory(Category category, String queryString){
		DataSource<DictItem> result = null;
		try{
			if(category == null)
				throw new AppException("Category can not be empty!");
			List<DictItem> items = this.dictItemService.findByCategory(category, queryString);
			//存入扩展项
			DataSource<DictItem> extendsItems = this.findExtendsItems(category);
			if(extendsItems != null){
				items.addAll(extendsItems.getDataSource());
			}
			//存入cache
			result = new CollectionDataSource<DictItem>(items);
			//
			Cache<String, DataSource<DictItem>> cache = this.getCache();
			if(cache != null && StringUtils.isEmpty(queryString)) {
				cache.put(category.getCode(), result);
			}
		}catch(Exception e){
			log.error(this, e);
		}
		if(result == null) {
			result = new EmptyDataSource<DictItem>();
		}
		return result;
	}
	
	/**
	 * 
	 * @modify wanghaifeng Jan 20, 2007 5:20:20 PM
	 * @param category
	 * @return
	 */
	private DataSource<DictItem> findExtendsItems(Category category){
		if(category == null || StringUtils.isEmpty(category.getQueryString())){
			return null;
		}
		List<DictItem> result = Utils.newArrayList();
		try{
			HibernateTemplate t = HibernateHelper.getHibernateTemplate();
			List list = t.find(category.getQueryString());
			for(Object o: list){
				if(o == null) continue;
				if(o instanceof whf.framework.meta.entity.Object){
					whf.framework.meta.entity.Object mo = (whf.framework.meta.entity.Object)o;
					result.add(new DictItem(category, mo.getName(), mo.getBoClassName()));
				} else if(o instanceof Entity){
					Entity bo = (Entity)o;
					result.add(new DictItem(category, bo.getName(), bo.getCode()));
				} else if(o.getClass().isArray()){
					Object[] arr = (Object[]) o;
					if(arr.length != 2){
						log.warn(o);
					} else {
						String n = arr[0] == null? "": arr[0].toString();
						String c = arr[1] == null? "": arr[1].toString();
						result.add(new DictItem(category, n, c));
					}
				} else {
					log.warn(o);
				}
			}
		}catch(Exception e){
			log.error(this, e);
		}
		return new CollectionDataSource<DictItem>(result);
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.ext.DictManager#findByCategoryCode(java.lang.String)
	 */
	public DataSource<DictItem> findByCategoryCode(String codeOrEnumClassName, String queryString){
		DictHelper helper = DictHelperFactory.getInstance().getDictHelper(codeOrEnumClassName);
		if(helper != null) return helper.getDictItems(queryString);
		//
		try{
			Cache<String, DataSource<DictItem>> cache = this.getCache();
			if(cache != null && cache.get(codeOrEnumClassName) != null && StringUtils.isEmpty(queryString)){
				return cache.get(codeOrEnumClassName);
			} else {
				Category category = this.categoryService.findByCode(codeOrEnumClassName);
				if(category == null)
					category = this.categoryService.findByEnumClassName(codeOrEnumClassName);
				if(category == null)
					throw new AppException("The category code or enum class is \" " + codeOrEnumClassName +"\" not found!");
				return this.findByCategory(category, queryString);
			}
		}catch(Exception e){
			log.error(this, e);
			return new EmptyDataSource<DictItem>();
		}
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.ext.DictManager#findByCategoryName(java.lang.String)
	 */
	public DataSource<DictItem> findByCategoryName(String name){
		try{
			List<Category> list = this.categoryService.find("t.name=?", name);
			if(list.size() > 0){
				Category category = (Category)list.get(0);
				return this.findByCategory(category, null);
			} else {
				return new EmptyDataSource<DictItem>();
			}
		}catch(Exception e){
			log.error(this, e);
			return new EmptyDataSource<DictItem>();
		}
	}

	/* (non-Javadoc)
	 * @see whf.framework.ext.DictManager#findByEnumClassName(java.lang.String)
	 */
	public DataSource<DictItem> findByEnumClassName(String className) {
		try{
			Category category = this.categoryService.findByEnumClassName(className);
			return this.findByCategory(category, null);
		}catch(Exception e){
			log.error(this, e);
			return new EmptyDataSource<DictItem>();
		}
	}
	
	public static void main(String[] args) throws Exception{
		DictManager dm = DictManagerImp.getDictManager();
		DataSource<DictItem> items = dm.findByCategoryCode("SYSTEM-DATATYPE", null);
		for(Iterator<DictItem> it = items.iterator(); it.hasNext(); ){
			DictItem item = it.next();
			System.out.println(item.getName()+" =\t" + item.getCode());
		}
	}
}
